[AWS Glue]ジョブの実行が”java.io.FileNotFoundException: No such file or directory”というエラーになる時は実行ロールの権限を確認しよう
こんにちは、CX事業本部の若槻です。
AWS Glueは、データ変換処理(ETL)をサーバーレスで実装できるAWSサービスです。
今回は、AWS Glueのジョブ実行がjava.io.FileNotFoundException: No such file or directory
というエラーになる際の対処方法を確認しました。
事象
Glueデータカタログから取得したデータの変換を行う下記のようなスクリプトのGlueジョブを作成しました。
import sys from awsglue.transforms import * from awsglue.utils import getResolvedOptions from pyspark.context import SparkContext from awsglue.context import GlueContext from awsglue.job import Job args = getResolvedOptions(sys.argv, ['JOB_NAME', 'GLUE_DATABASE_NAME', 'SRC_GLUE_TABLE_NAME', 'DEST_GLUE_TABLE_NAME']) sc = SparkContext() glueContext = GlueContext(sc) spark = glueContext.spark_session job = Job(glueContext) job.init(args['JOB_NAME'], args) datasource0 = glueContext.create_dynamic_frame.from_catalog(database = args['GLUE_DATABASE_NAME'], table_name = args['SRC_GLUE_TABLE_NAME'], transformation_ctx = "datasource0") applymapping1 = ApplyMapping.apply(frame = datasource0, mappings = [("端末id", "string", "device_id", "string"), ("イベント日時", "bigint", "timestamp", "bigint"), ("状態", "string", "status", "string")], transformation_ctx = "applymapping1") selectfields2 = SelectFields.apply(frame = applymapping1, paths = ["device_id", "timestamp", "status"], transformation_ctx = "selectfields2") resolvechoice3 = ResolveChoice.apply(frame = selectfields2, choice = "MATCH_CATALOG", database = args['GLUE_DATABASE_NAME'], table_name = args['DEST_GLUE_TABLE_NAME'], transformation_ctx = "resolvechoice3") datasink4 = glueContext.write_dynamic_frame.from_catalog(frame = resolvechoice3, database = args['GLUE_DATABASE_NAME'], table_name = args['DEST_GLUE_TABLE_NAME'], transformation_ctx = "datasink4") job.commit()
しかし、上記ジョブを実行したところ次のようなエラーとなりました。
java.io.FileNotFoundException: No such file or directory 's3://devices-raw-data-XXXXXXXXXXXX-ap-northeast-1/utf8-data/f28f7767-0088-4bb7-b015-ce548fb350c8'
調査、解決
エラーはcreate_dynamic_frame.from_catalog()
によるデータソースのS3バケットからのデータ取得時に発生しているようです。しかし、取得したいデータのファイル名(f28f7767-0088-4bb7-b015-ce548fb350c8)までは取れているのにそんなファイルが無いってどういうこと?となり最初は原因がさっぱり分かりませんでした。
そして同様の事象を検索してみると以下の質問投稿がありました。
質問に対する回答として、権限の問題でGetObjectが足りていないのではないか?とコメントが付いていますね。
it was indeed a permission's issue. As it turns out, I forgot to add specific S3 permissions for the objects (GetObject) inside the bucket and not only to the bucket itself.
ジョブ実行ロールはCloudFormationで作成したので、リソースの定義を再確認してみるとビンゴでした。下記の通りデータソースのS3バケットのキーに対してs3:PutObject
権限しか割り当たっていませんでした。
//<Other Resources> ExecuteDevicesGlueJobRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - glue.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyName: execute-devices-glue-job-policy PolicyDocument: Version: 2012-10-17 Statement: //<Other Statements> - Effect: Allow Action: - s3:PutObject Resource: - !Sub arn:aws:s3:::${DevicesRawDataBucket}/utf8-data/*
そこでs3:GetObject
の権限を付与する変更を行いました。
//<Other Resources> ExecuteDevicesGlueJobRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - glue.amazonaws.com Action: - sts:AssumeRole Policies: - PolicyName: execute-devices-glue-job-policy PolicyDocument: Version: 2012-10-17 Statement: //<Other Statements> - Effect: Allow Action: - s3:PutObject - s3:GetObject Resource: - !Sub arn:aws:s3:::${DevicesRawDataBucket}/utf8-data/*
するとジョブが正常に実行できるようになり解決できました。
おわりに
AWS Glueのジョブ実行が"java.io.FileNotFoundException: No such file or directory"というエラーになる際の対処方法を確認しました。
エラー内容から権限を確認しようという発想にすぐに至らなかったため調査が長期化しそうでしたが、先人の投稿をもとに解決できて良かったです。
以上